#pragma once
#include"log.hpp"
#include"common.hpp"
#include "inetaddr.hpp"
#include <thread>

class  TcpServer : public NoCopy
{ 
public:
    TcpServer(uint16_t port)
    :_port(port)
    ,_isrunning(false)
    {

    }

    ~TcpServer()
    {
        
    }

    void Init()
    {
        int listensockfd = socket(AF_INET,SOCK_STREAM,0);
        if(listensockfd == -1)
        {
            LOG(LogLevel::FATAL) << "server socket error"; 
            exit(static_cast<int>(ExitCode::SOCKET_ERR));
        }
        _listensockfd = listensockfd;
        LOG(LogLevel::INFO) << "server socket success";
        InetAddr local(_port);
        int  n = bind(_listensockfd,(struct sockaddr*)&local.GetAddr(),local.Getlen());
        if(n == -1)
        {
            LOG(LogLevel::FATAL) << "server bind error";
            exit(static_cast<int>(ExitCode::BIND_ERR)); 
        }
        LOG(LogLevel::INFO) << "server bind success";
        int m = listen(_listensockfd,8);
        if(m == -1)
        {
            LOG(LogLevel::FATAL) << "server listen error";
            exit(static_cast<int>(ExitCode::LISTEN_ERR)); 
        }
        LOG(LogLevel::INFO) << "server listen success";
    }

    void Server(int sockfd,const InetAddr& peer)
    {

        char buffer[1024];
        while(true)
        {
            int n = read(sockfd,buffer,sizeof(buffer) - 1);
            if(n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::DEBUG) << "收到一条消息，来自[" << peer.GetIp() << ":" << peer.GetPort() << "]# " << buffer; 
                std::string echo("server echo#");
                echo += buffer;
                write(sockfd,echo.c_str(),echo.size());
            }
            else if(n == 0)
            {
                LOG(LogLevel::DEBUG) << "客户端退出 " << peer.GetIp() << ":" << peer.GetPort(); 
                close(sockfd);
                break;
            }
        }
    }

    void Run()
    {
        _isrunning = true;
        while(_isrunning)
        {
            InetAddr peer;
            socklen_t len =  peer.Getlen();
            int sockfd = accept(_listensockfd,(struct sockaddr*)&peer.GetAddr(),&len);
            if(sockfd == -1)
            {
                LOG(LogLevel::WARNING) << "server accept error";
                continue;
            }
            peer.Ntop();
            LOG(LogLevel::INFO) << "server accept success ,peer#" << peer.GetIp() << ":" << peer.GetPort();
            std::thread t(&TcpServer::Server,this,sockfd,peer);
            t.detach();
        }
    }

private:
    uint16_t _port;
    bool _isrunning;
    int _listensockfd;
};